package com.ndood.admin.core.web.aspect;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import com.google.gson.Gson;
import com.ndood.admin.core.util.IpInfoUtil;
import com.ndood.admin.pojo.system.LogPo;
import com.ndood.admin.service.system.SystemLogService;
import com.ndood.core.utils.ThreadPoolUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 创建自定义切片类，用于打印日志
 */
@Component
@Aspect
@Slf4j
public class OptionalLogAspect {
	
	private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime");
	
	@Autowired
	private SystemLogService systemLogService; 
	
	@Autowired(required=false)
    private HttpServletRequest request;
	
	/**
     * Controller层切点,注解方式
     */
    @Pointcut("execution(* com.ndood.admin.controller.*.*Controller.*(..))")
    public void controllerAspect() {}
	
	/**
     * 前置通知 (在方法执行之前返回)用于拦截Controller层记录用户的操作的开始时间
     * @param joinPoint 切点
     * @throws InterruptedException
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) throws InterruptedException{
        //线程绑定变量（该数据只有当前请求的线程可见）
        Date beginTime=new Date();
        beginTimeThreadLocal.set(beginTime);
    }
	
    /**
     * 保存日志
     */
    private static class SaveAccountLogThread implements Runnable {

        private LogPo log;
        private SystemLogService systemLogService;

        public SaveAccountLogThread(LogPo log, SystemLogService systemLogService) {
            this.log = log;
            this.systemLogService = systemLogService;
        }

        @Override
        public void run() {
        	systemLogService.makeLog(log);
        }
        
    }
    
    @After("controllerAspect()")
    public void after(JoinPoint joinPoint){
    	Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    	if(obj==null || !(obj instanceof UserDetails)) {
    		return;
    	}
    	
    	UserDetails user = (UserDetails) obj;
    	String username= user.getUsername(); // 其实是userId
    	
    	if(StringUtils.isBlank(username)) {
    		return;
    	}

    	LogPo logPo = new LogPo();
    	
    	logPo.setUsername(username);
    	logPo.setCreateTime(beginTimeThreadLocal.get());
    	logPo.setIp(IpInfoUtil.getIpAddr(request));
    	//logPo.setRequestParam(Lists.newArrayList(joinPoint.getArgs()).toString());
    	logPo.setRequestType(request.getMethod());
    	logPo.setRequestUrl(request.getRequestURI());
    	logPo.setIpInfo(IpInfoUtil.getIpCity(IpInfoUtil.getIpAddr(request)));
        long beginTime = beginTimeThreadLocal.get().getTime();
        long endTime = System.currentTimeMillis();
        Long logElapsedTime = endTime - beginTime;
        log.info("["+logElapsedTime+"]"+new Gson().toJson(logPo));

        //调用线程保存至ES
        ThreadPoolUtil.getPool().execute(new SaveAccountLogThread(logPo, systemLogService));
        
    }
    
}